package com.googlecode.cswish;

import java.io.File;
import java.lang.reflect.Method;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.apache.struts2.StrutsStatics;
import org.apache.struts2.StrutsTestCase;
import org.apache.struts2.views.jsp.StrutsMockServletContext;
import org.junit.After;
import org.junit.Before;

import com.googlecode.cswish.annotation.Protected;
import com.googlecode.cswish.struts.BaseActionSupport;
import com.googlecode.cswish.struts.hibernate.HibernateConfiguration;
import com.googlecode.cswish.struts.spring.BeanIntrospector;
import com.googlecode.cswish.struts.spring.DFactory;
import com.googlecode.cswish.struts.spring.GenericService;
import com.googlecode.cswish.struts.spring.ObjectFactory;
import com.googlecode.cswish.util.FrameConstant;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.inject.Container;

/**
 * Wrapper the StrutsTestCase, convert it from JUnit3 to JUnit4
 * 
 * @author Jerry.Feng 2008-11-23
 */
//@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(locations={"classpath*:/applicationContext.xml"})
public class BaseStrutsTestCase extends BaseSpringTestCase {	//AbstractTransactionalDataSourceSpringContextTests

	private final static Logger logger = Logger.getLogger(BaseStrutsTestCase.class);
	
	private static StrutsTestCase instance;

	protected static Container container;
	
	@Resource
	protected DFactory dfactory;
	
	@Resource
	protected BeanIntrospector beanIntrospector;
	
	@Before
	public void setUp() throws Exception {
		if (instance != null) {
			super.setUp();
			return;
		}
		
		instance = new StrutsTestCase();
		instance.setUp();
		container = instance.getContainer();
        StrutsMockServletContext servletContext = new StrutsMockServletContext();
        String path = new File("nosuchfile.properties").getAbsolutePath();
        servletContext.setRealPath(path);
        servletContext.setServletInfo("Resin");
        servletContext.setContextPath("/");
        ActionContext.getContext().put(StrutsStatics.SERVLET_CONTEXT, servletContext);
        
        objectFactory = (ObjectFactory) container.getInstance(
        		com.opensymphony.xwork2.ObjectFactory.class);
        super.setUp();
    }
	
	public Class<?> getActionClass(Class<?> serviceClass, String methodName) {
		Method matchedMethod = null;
		if (beanIntrospector.isService(serviceClass.getName()) >= 0)
		{
			matchedMethod = getMethod(serviceClass, methodName);
		} else {
			try {
				serviceClass = objectFactory.getClassInstance(GenericService.class.getName());
				
				matchedMethod = getMethod(serviceClass, methodName);
			} catch (ClassNotFoundException ex) {
				logger.error("Can't find generic service", ex);
			}
		}
		
		String simpleName = beanIntrospector.getSimpleName(serviceClass.getName());
		
		String actionName = beanIntrospector.getActionName(simpleName + '.' + methodName);
		return dfactory.convert2Class(serviceClass, matchedMethod, actionName,
				BaseActionSupport.class, "execute", true, Action.SUCCESS);
	}
	
	protected Method getMethod(Class<?> clazz, String method) {
		Method[] methods = clazz.getDeclaredMethods();
		Method found = null;
		for (Method m : methods) {
			if (m.getAnnotation(Protected.class) == null) {
				if (method.equals(m.getName())) {
					found = m;
					break;
				}
			}
		}
		
		// use DFactory create a new method according to current method interface template
		if (found == null && method.startsWith(FrameConstant.ACTION_PREPARE)) {
			found = getMethod(clazz, 
					method.substring(FrameConstant.ACTION_PREPARE.length()));
		}
		return found;
	}
	
	@After
	public void tearDown() throws Exception {
		super.tearDown();
		//instance.tearDown();
	}
}